package top.tenebrous.termbor.rpc.consumer;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.tenebrous.termbor.rpc.common.exceptiion.RegistryException;
import top.tenebrous.termbor.rpc.consumer.manager.RpcConsumerManager;
import top.tenebrous.termbor.rpc.proxy.async.IAsyncObjectProxy;
import top.tenebrous.termbor.rpc.proxy.config.ProxyConfig;
import top.tenebrous.termbor.rpc.proxy.factory.ProxyFactory;
import top.tenebrous.termbor.rpc.proxy.object.ObjectProxy;
import top.tenebrous.termbor.rpc.registry.RegistryService;
import top.tenebrous.termbor.rpc.registry.config.RegistryConfig;
import top.tenebrous.termbor.rpc.spi.loader.ExtensionLoader;

/**
 * @program: termbor-rpc
 * @description:
 * @author: yazhang6
 * @create: 2024-05-22 17:45
 **/
public class RpcClient {

    private final Logger logger = LoggerFactory.getLogger(RpcClient.class);

    private String serviceVersion;

    private String serviceGroup;

    private String serializationType;

    private long timeout;

    private boolean async;

    private boolean oneway;

    private RegistryService registryService;

    private String proxy;

    public RpcClient(String registryAddress, String registryType , String registryLoadBalanceType, String proxy,String serviceVersion, String serviceGroup, String serializationType, long timeout, boolean async,
        boolean oneway) {
        this.serviceVersion = serviceVersion;
        this.proxy = proxy;
        this.serviceGroup = serviceGroup;
        this.serializationType = serializationType;
        this.timeout = timeout;
        this.async = async;
        this.oneway = oneway;
        this.registryService = this.getRegistryService(registryAddress, registryType, registryLoadBalanceType);
    }

    private RegistryService getRegistryService(String registryAddress, String registryType, String registryLoadBalanceType) {
        if (StringUtils.isEmpty(registryType)) {
            throw new IllegalStateException("registry type is null");
        }
        RegistryService registryService = ExtensionLoader.getExtension(RegistryService.class, registryType);
        try {
            registryService.init(new RegistryConfig(registryAddress, registryType, registryLoadBalanceType));
        } catch (Exception e) {
            logger.error("RpcClient init registry service throws exception:{}", e);
            throw new RegistryException(e.getMessage(), e);
        }
        return registryService;
    }

    public <T> T create(Class<T> interfaceClass) {
        ProxyFactory<T> proxyFactory = ExtensionLoader.getExtension(ProxyFactory.class, proxy);
        proxyFactory.init(new ProxyConfig<>(interfaceClass, serviceVersion, serviceGroup, serializationType, timeout, this.registryService, RpcConsumerManager.getInstance(), async, oneway));
        return proxyFactory.getProxy(interfaceClass);
    }

    public void shutdown() {
        RpcConsumerManager.getInstance().close();
    }

    public <T>IAsyncObjectProxy createAsync(Class<T> interfaceClass) {
        return new ObjectProxy<T>(interfaceClass, serviceVersion, serviceGroup, timeout, registryService,RpcConsumerManager.getInstance(), serializationType,  async, oneway);
    }
}
